# -*- coding: utf-8 -*-
"""
工具函数模块
提供项目中使用的各种工具函数
"""

import re
import os
import logging
from pathlib import Path
from typing import Optional, Union
from datetime import datetime


def validate_bilibili_url(url: str) -> bool:
    """
    验证B站视频URL格式是否正确
    
    Args:
        url: 待验证的URL字符串
        
    Returns:
        bool: URL格式是否正确
    """
    if not url or not isinstance(url, str):
        return False
    
    # B站视频URL的正则表达式模式
    patterns = [
        r'https?://www\.bilibili\.com/video/[Bb][Vv][0-9A-Za-z]+',  # BV号
        r'https?://www\.bilibili\.com/video/av\d+',  # av号
        r'https?://b23\.tv/[0-9A-Za-z]+',  # 短链接
        r'https?://m\.bilibili\.com/video/[Bb][Vv][0-9A-Za-z]+',  # 移动端
        r'https?://space\.bilibili\.com/\d+/video',  # 用户空间视频
    ]
    
    return any(re.match(pattern, url.strip()) for pattern in patterns)


def extract_video_id(url: str) -> Optional[str]:
    """
    从B站URL中提取视频ID
    
    Args:
        url: B站视频URL
        
    Returns:
        str: 视频ID（BV号或av号），如果提取失败返回None
    """
    if not validate_bilibili_url(url):
        return None
    
    # 提取BV号
    bv_match = re.search(r'[Bb][Vv][0-9A-Za-z]+', url)
    if bv_match:
        return bv_match.group(0)
    
    # 提取av号
    av_match = re.search(r'av(\d+)', url)
    if av_match:
        return f"av{av_match.group(1)}"
    
    return None


def validate_file_path(path: Union[str, Path]) -> bool:
    """
    验证文件路径是否有效
    
    Args:
        path: 文件路径
        
    Returns:
        bool: 路径是否有效
    """
    try:
        path_obj = Path(path)
        # 检查父目录是否存在或可创建
        parent_dir = path_obj.parent
        return parent_dir.exists() or parent_dir.is_dir()
    except (OSError, ValueError):
        return False


def ensure_directory(path: Union[str, Path]) -> bool:
    """
    确保目录存在，如果不存在则创建
    
    Args:
        path: 目录路径
        
    Returns:
        bool: 是否成功创建或目录已存在
    """
    try:
        path_obj = Path(path)
        path_obj.mkdir(parents=True, exist_ok=True)
        return True
    except (OSError, PermissionError):
        return False


def get_safe_filename(filename: str) -> str:
    """
    获取安全的文件名，移除或替换非法字符
    
    Args:
        filename: 原始文件名
        
    Returns:
        str: 安全的文件名
    """
    # 移除或替换Windows文件名中的非法字符
    illegal_chars = r'[<>:"/\\|?*]'
    safe_name = re.sub(illegal_chars, '_', filename)
    
    # 移除前后空格和点号
    safe_name = safe_name.strip(' .')
    
    # 确保文件名不为空
    if not safe_name:
        safe_name = 'untitled'
    
    # 限制文件名长度
    if len(safe_name) > 200:
        safe_name = safe_name[:200]
    
    return safe_name


def format_file_size(size_bytes: int) -> str:
    """
    格式化文件大小为人类可读的格式
    
    Args:
        size_bytes: 文件大小（字节）
        
    Returns:
        str: 格式化后的文件大小字符串
    """
    if size_bytes == 0:
        return "0 B"
    
    size_names = ["B", "KB", "MB", "GB", "TB"]
    size_index = 0
    size = float(size_bytes)
    
    while size >= 1024.0 and size_index < len(size_names) - 1:
        size /= 1024.0
        size_index += 1
    
    if size_index == 0:
        return f"{int(size)} {size_names[size_index]}"
    else:
        return f"{size:.2f} {size_names[size_index]}"


def format_duration(seconds: int) -> str:
    """
    格式化时长为 HH:MM:SS 格式
    
    Args:
        seconds: 时长（秒）
        
    Returns:
        str: 格式化后的时长字符串
    """
    if seconds < 0:
        return "00:00"
    
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    seconds = seconds % 60
    
    if hours > 0:
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
    else:
        return f"{minutes:02d}:{seconds:02d}"


def format_speed(bytes_per_second: float) -> str:
    """
    格式化下载速度
    
    Args:
        bytes_per_second: 每秒字节数
        
    Returns:
        str: 格式化后的速度字符串
    """
    if bytes_per_second <= 0:
        return "0 B/s"
    
    return f"{format_file_size(int(bytes_per_second))}/s"


def calculate_eta(downloaded: int, total: int, speed: float) -> str:
    """
    计算预计剩余时间
    
    Args:
        downloaded: 已下载字节数
        total: 总字节数
        speed: 下载速度（字节/秒）
        
    Returns:
        str: 预计剩余时间字符串
    """
    if speed <= 0 or downloaded >= total:
        return "--:--"
    
    remaining_bytes = total - downloaded
    eta_seconds = int(remaining_bytes / speed)
    
    return format_duration(eta_seconds)


def setup_logger(name: str, log_file: Optional[str] = None, level: int = logging.INFO) -> logging.Logger:
    """
    设置日志记录器
    
    Args:
        name: 日志记录器名称
        log_file: 日志文件路径（可选）
        level: 日志级别
        
    Returns:
        logging.Logger: 配置好的日志记录器
    """
    logger = logging.getLogger(name)
    logger.setLevel(level)
    
    # 避免重复添加处理器
    if logger.handlers:
        return logger
    
    # 创建格式化器
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    
    # 控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setLevel(level)
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)
    
    # 文件处理器（如果指定了日志文件）
    if log_file:
        try:
            # 确保日志目录存在
            log_path = Path(log_file)
            ensure_directory(log_path.parent)
            
            file_handler = logging.FileHandler(log_file, encoding='utf-8')
            file_handler.setLevel(level)
            file_handler.setFormatter(formatter)
            logger.addHandler(file_handler)
        except Exception as e:
            logger.warning(f"无法创建日志文件 {log_file}: {e}")
    
    return logger


def get_timestamp() -> str:
    """
    获取当前时间戳字符串
    
    Returns:
        str: 格式化的时间戳
    """
    return datetime.now().strftime('%Y%m%d_%H%M%S')


def parse_quality_description(quality_desc: str) -> dict:
    """
    解析视频质量描述
    
    Args:
        quality_desc: 质量描述字符串
        
    Returns:
        dict: 包含分辨率、帧率等信息的字典
    """
    result = {
        'resolution': 'unknown',
        'fps': 0,
        'quality_id': 0
    }
    
    # 常见的质量映射
    quality_map = {
        '1080P': {'resolution': '1920x1080', 'quality_id': 80},
        '720P': {'resolution': '1280x720', 'quality_id': 64},
        '480P': {'resolution': '854x480', 'quality_id': 32},
        '360P': {'resolution': '640x360', 'quality_id': 16},
        '240P': {'resolution': '426x240', 'quality_id': 6}
    }
    
    for quality, info in quality_map.items():
        if quality in quality_desc:
            result.update(info)
            break
    
    # 提取帧率信息
    fps_match = re.search(r'(\d+)fps', quality_desc, re.IGNORECASE)
    if fps_match:
        result['fps'] = int(fps_match.group(1))
    
    return result